/*
 * 初始化配置文件
 * 配置文件的位置固定
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "project.h"
#include "util.h"

typedef struct st_stack
{
	int top;
	int depth;
	int state;
	int *stack;
}* Stack;

#define False -1
#define True 1
#define mid 0

char *object, *value;

const char *names[] = {
	"FILEPATH",
	"PROFILEPATH",
	"BACKFILE",
	"HASH_TABLE_SIZE",
	"BLOCK_SIZE",
	"FILENAME_LENGTH",
	"SECTION_LENGTH",
	"BUFFER_FILE_SIZE",
	"BUFFER_INVALID_TIME",
	"MAX_BUFFER_SIZE",
	"BACKUP_TIME"
};

enum json_states
{
	GO,
	VA,		//value
	ST,		//string
	OB,		//object
	IN,		//integer
	AR,		//array
	TR,		//true
	FA,		//false
	NU,		//null
	NO,		//note
	WN,		//wanted note
	NR_ITEMS
};

enum modes
{
	MODE_ARRAY,
	MODE_DONE,
	MODE_KEY,
	MODE_OBJECT,
};

Stack
new_stack (int depth)
{
	Stack sc = (Stack) malloc(sizeof(struct st_stack));
	if (sc == NULL)
	{
		fprintf(stderr, "out of memory\n");
		exit(-1);
	}

	sc->depth = depth;
	sc->top = -1;
	sc->state = GO;
	sc->stack = (int *) malloc (depth * sizeof(int));

	return sc;
}

void
free_stack (Stack sc)
{
	if (sc == NULL)
		return;
	if (sc->stack)
		free(sc->stack);
	free(sc);
}

int
push (Stack sc, int element)
{
	sc->top++;
	if (sc->top >= sc->depth)
		return False;
	sc->stack[sc->top] = element;
	return True;
}

int
pop (Stack sc)
{
	if (sc->top < 0)
		return False;
	sc->top--;
	return True;
}

int 
top (Stack sc)
{
	return sc->stack[sc->top];
}

void
get_object (Stack sc)
{
	object = (char *)realloc(object, sc->top + 2);
	memset(object, 0, sc->top+2);
	while (sc->top >= 0)
	{
		object[sc->top] = top(sc);
		pop(sc);
	}
}

void
get_value (Stack sc)
{
	value = (char *) realloc (value, sc->top + 2);
	memset(value, 0, sc->top+2);
	while (sc->top >= 0)
	{
		value[sc->top] = top(sc);
		pop(sc);
	}
}

int
compare_name ()
{
	int i;
	for (i = 0; i < 11; i++)
		if (strcmp(object, names[i]) == 0)
			break;
	return i;
}

int 
getValueInteger ()
{
	int ret = 0, pos = 0;
	while (*(value+pos))
	{
		ret = ret * 10 + *(value+pos) - '0';
		pos++;
	}
	return ret;
}

void
set_value ()
{
	int i;
	i = compare_name();
	switch (i)
	{
		case 0:
			FILEPATH = strdup(value);
			break;
		case 1:
			PROFILEPATH = strdup(value);
			break;
		case 2:
			BACKFILE = strdup(value);
			break;
		case 3:
			HASH_TABLE_SIZE = getValueInteger();
			break;
		case 4:
			BLOCK_SIZE = getValueInteger();
			break;
		case 5:
			FILENAME_LENGTH = getValueInteger();
			break;
		case 6:
			SECTION_LENGTH = getValueInteger();
			break;
		case 7:
		 	BUFFER_FILE_SIZE = getValueInteger();
		 	break;
		case 8:
			BUFFER_INVALID_TIME = getValueInteger();
			break;
		case 9:
			MAX_BUFFER_SIZE = getValueInteger();
			break;
		case 10:
			BACKUP_TIME = getValueInteger();
			break;
		default:
			break;
	}
}

int
json_checker (Stack sc, int next_char)
{
	if (next_char < 0)
		return False;
	if (next_char == '/' && sc->state == GO)
	{
		sc->state = NO;
		return True;
	}
	if (next_char == '\n' && sc->state == NO)
	{
		sc->state = GO;
		return True;
	}
	if (sc->state == NO)
		return True;
	if (sc->state == GO && next_char == '\t' || next_char == ' ' || next_char == '\n' || next_char == ',')
		return True;
	if (next_char == '"' && sc->state == GO)
	{
		sc->state = OB;
		return True;
	}
	if (next_char == '"' && sc->state == OB)
	{
		get_object(sc);
		sc->state = VA;
		return True;
	}
	if (sc->state == VA && next_char == ':' || next_char == ' ')
		return True;
	if (sc->state == VA && next_char == '"')
	{
		sc->state = ST;
		return True;
	}
	if (sc->state == VA && isdigit(next_char))
	{
		sc->state = IN;
		push(sc, next_char);
		return True;
	}
	if (sc->state == ST && next_char == '"')
	{
		get_value(sc);
		sc->state = GO;
		return mid;
	}
	if (sc->state == IN && !isdigit(next_char))
	{
		get_value(sc);
		sc->state = GO;
		return mid;
	}
	push(sc, next_char);

	return True;
}

void
show ()
{
	printf("FILEPATH: %s\n", FILEPATH);
	printf("PROFILEPATH: %s\n", PROFILEPATH);
	printf("BACKFILE: %s\n", BACKFILE);
	printf("HASH_TABLE_SIZE: %d\n", HASH_TABLE_SIZE);
	printf("BLOCK_SIZE: %d\n", BLOCK_SIZE);
	printf("FILENAME_LENGTH: %d\n", FILENAME_LENGTH);
	printf("SECTION_LENGTH: %d\n", SECTION_LENGTH);
	printf("BACKUP_TIME: %d\n", BACKUP_TIME);
	printf("BUFFER_FILE_SIZE: %d\n", BUFFER_FILE_SIZE);
	printf("BUFFER_INVALID_TIME: %d\n", BUFFER_INVALID_TIME);
	printf("MAX_BUFFER_SIZE: %lu\n", MAX_BUFFER_SIZE);
}

void
init_profile ()
{
	FILE *fp = fopen("/home/jadsin/NetBeansProjects/disk/profile/profile.cnf", "r");
	int next_char = fgetc(fp);

	Stack sc = new_stack(255);

	for (;;)
	{
		next_char = fgetc(fp);
		if (json_checker(sc, next_char) == mid)
		{
			set_value();
		}
		if (next_char == '}')
			break;
	}
	free_stack(sc);
	free(object);
	free(value);
	fclose(fp);
	//show();
}